昨天有提到,專案上遇到兩個問題
今天實測家中的網路,112MB 的模型,不可能需要這麼多時間,所以嘗試做了點改變
我直接在瀏覽器新分頁,開模型檔的網址(https://smallhand.github.io/drone_threejs/blender_output.glb),不經過我寫的程式。結果光是把這個檔案載入完,就花了 22 分鐘。
所以問題不在 Three.js 的程式,也不在瀏覽器解析模型,而是檔案從 GitHub 傳到我的電腦很慢。
我用 Speedtest 測了一下,下載 298.20 Mbps、上傳 97.86 Mbps,Ping 5 ms。298 Mbps 換算約每秒 37 MB(÷ 8),理論上 50 MB 只要一兩秒。可是實際花了 22 分鐘,差了好幾百倍,所以不是我的整體網速不夠。
我用 curl 這個指令列工具,不經過瀏覽器,直接測連線速度:
curl.exe -4 -m 20 -o NUL -w "速度 %{speed_download}`n" 網址
-4:只用 IPv4 連線。-m 20:最多跑 20 秒就停止,不用等載完。-o NUL:載入的內容直接丟掉,不存檔。-w "...":結束後印出平均速度(單位是位元組/秒)。另外,我的手機用行動網路打開同一個網址,不到 1 分鐘就載入完。
所以結論是:同一個網址,在我這台電腦(有線 HiNet)上特別慢,連到別的網站卻很快。我無法確定原因是我家到 GitHub 的網路路徑,還是我電腦上的某個設定,因為我沒有在同一台電腦上換一條網路比較。但這已經足夠讓我決定:模型不要再放在 GitHub Pages。
我把問題和測試結果拿去請教 AI,AI 列了幾個放置模型的地方:GitHub Releases、Cloudflare R2、Cloudflare Pages、jsDelivr。我最後選 Cloudflare R2,原因如下。
上一節的測試,連 Cloudflare 是每秒 27 MB,連 GitHub Pages 只有每秒約 0.08 MB。差別這麼大,搬到 Cloudflare 的網路上是最直接的做法。
依 Cloudflare 官方的 R2 定價文件,每月免費額度是:
| 項目 | 免費額度 |
|---|---|
| 儲存 | 10 GB |
| Class A 操作 | 100 萬次 |
| Class B 操作 | 1,000 萬次 |
| 流量(egress) | 免費 |
文件對流量的說明是:
There are no charges for egress bandwidth for any storage class.
一個 50 MB 到 112 MB 的模型,只占儲存額度的一小部分。每個使用者載入一次模型就是一次流量,流量不收費,對這種「檔案大、人很多」的用途很重要。
R2 官方的限制文件寫單一物件上限是 5 TiB。模型檔不經過 git,就不會再被 GitHub 擋,原本想用的 111.97 MB 的 3D model 也可以放。
| 選項 | 沒選的原因 |
|---|---|
| Cloudflare Pages | 單一檔案上限 25 MiB(文件),我的模型放不進去 |
| GitHub Releases | 官方文件寫單檔小於 2 GiB(文件),但還是在 GitHub 上,我無法確定會不會一樣慢 |
| jsDelivr | 我沒有查到它對檔案大小的限制,不確定能不能放這麼大的檔案 |
r2.dev,官方文件說:「Public access through r2.dev subdomains is rate-limited and should only be used for development purposes.」也就是它有速率限制,只適合開發用途。正式上線要綁自己的網域。我目前是做展示用,先用 r2.dev。註冊 Cloudflare 後,到 Storage & databases → R2 object storage,完成訂閱後建立 bucket(存放檔案的空間)。依官方文件,名稱規則:
Bucket names can only contain lowercase letters (a-z), numbers (0-9), and hyphens (-).
名稱不能以連字號開頭或結尾,長度 3 到 63 個字元。
依官方文件:進入 bucket → Upload → 拖曳檔案,或選 select from computer。
依官方文件:bucket → Settings → 啟用 public development URL,輸入 allow 確認。啟用後會得到一個 https://pub-xxxxxxxx.r2.dev 的網址,模型的完整網址就是這個網址加上檔名。
這時我直接在瀏覽器開這個網址,檔案可以載入。
我把 main.js 裡的模型路徑改成 R2 的網址,網頁執行時,Console 出現:
Access to fetch at 'https://pub-xxxxxxxx.r2.dev/3d_unseen_true.glb' from origin 'http://(我本機測試用的 IP 與 port)' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
意思是:我的網頁在 A 網站(本機測試的網址)執行,要去載入 B 網站(r2.dev)的檔案,瀏覽器會先檢查 B 有沒有明確允許 A 來載入。R2 回應裡沒有 Access-Control-Allow-Origin,所以瀏覽器擋下來。
我直接在網址列開檔案可以載入,是因為那是我自己點開的網址,不是網頁裡的程式去讀取。
依官方 CORS 文件:bucket → Settings → CORS Policy → Add CORS policy → JSON 分頁貼上並 Save。
[
{
"AllowedOrigins": [
"http://(我本機測試用的 IP 與 port)",
"https://smallhand.github.io"
],
"AllowedMethods": ["GET", "HEAD"]
}
]
AllowedOrigins:允許哪些網站來載入。第一個是我在家裡測試時,網頁的 IP 和我開的 port;第二個是部署後的網站。文件說值必須是 scheme://host[:port],不能有路徑或結尾斜線,所以第二個不能寫成 https://smallhand.github.io/drone_threejs/。AllowedMethods:載入模型只需要讀取,所以是 GET 和 HEAD。| 項目 | 結果 |
|---|---|
| 電腦 | 幾秒內載入成功 |
| 手機 | 比電腦慢一些,接近 1 分鐘 |
和一開始放在 GitHub Pages 的 22 分鐘相比,差別很大。
AllowedOrigins 要跟瀏覽器網址列上的來源完全一致。模型載入穩定後,明天換用手機開啟專案,看是否能正常移動、旋轉模型,然後點擊彩蛋時,是否能認出這個事件